package com.miku.blog.config;

import com.miku.blog.domain.pojo.LoginUser;
import com.miku.blog.domain.Role;
import com.miku.blog.domain.UserAuth;
import com.miku.blog.eume.HttpStatusEnum;
import com.miku.blog.exception.SystemException;
import com.miku.blog.filter.AuthenticationTokenFilter;
import com.miku.blog.filter.ResourceAuthoritiesFilter;
import com.miku.blog.handler.security.AccessDeniedHandlerImpl;
import com.miku.blog.handler.security.AuthenticationEntryPointImpl;
import com.miku.blog.mapper.RoleMapper;
import com.miku.blog.service.RoleService;
import com.miku.blog.service.UserAuthService;
import com.miku.blog.utils.EmailUtils;
import com.miku.blog.utils.RedisCache;
import com.miku.blog.utils.UserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.util.List;

/**
 * @author shkstart
 * @create ${}YEAR-05-10 20:06
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)//开启全局方法权限认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserAuthService userAuthService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private RedisCache redisCache;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()

                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//                .sessionFixation()
//                .none()

//                .sessionAuthenticationStrategy()

                .and()
                .authorizeRequests()
//                .antMatchers("/login")
//                .anonymous()//登录界面匿名访问
//
//                .antMatchers("/admin/**")
//                .authenticated()//后台地址需要认证

//                .antMatchers("/swagger**/**","/v3/api-docs")
//                .permitAll()//放行swagger API文档地址

                .anyRequest()
                .permitAll();

        //禁用默认注销接口logout
        http.logout().disable();

        http.addFilterBefore(new AuthenticationTokenFilter(redisCache,passwordEncoder()),UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(new ResourceAuthoritiesFilter(redisCache),AuthenticationTokenFilter.class);

        http.exceptionHandling()
                .authenticationEntryPoint(new AuthenticationEntryPointImpl())
                .accessDeniedHandler(new AccessDeniedHandlerImpl());

        http.cors();//允许跨域访问
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    @Override
    public UserDetailsService userDetailsServiceBean() throws Exception {
        UserDetailsService userDetailsService = new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                UserAuth userAuth;
                if (EmailUtils.checkEmail(username)){
                    userAuth = userAuthService.getUserAuthByEmail(username);
                }else {
                    userAuth = userAuthService.getUserAuthByUserName(username);
                }
                if (userAuth == null){
                    throw new SystemException(HttpStatusEnum.LOGIN_USERNAME_NOTEXISTS);
                }

                RoleMapper roleMapper = (RoleMapper) roleService.getBaseMapper();
                Role role = roleMapper.getRoleByUserId(userAuth.getId());

                return new LoginUser(userAuth,role);
            }
        };
        return userDetailsService;
    }
}
